package com.franklin.java.api.mybatis.dom.utils;

import com.flychord.jdk.util.tuple.Tuple2;
import com.franklin.plugins.common.collection.PrettyArrayList;
import com.franklin.java.api.mybatis.dom.franklin.MyMapper;
import com.franklin.java.api.mybatis.dom.model.Mapper;
import com.franklin.java.utils.DomUtils;
import com.franklin.java.utils.PsiUtils;
import com.franklin.plugins.common.utils.DataCheckUtils;
import com.franklin.plugins.common.utils.StringHelper;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.NotNull;

import java.util.*;
import java.util.stream.Collectors;

import static com.flychord.jdk.util.tuple.TupleAble.tuple;

/**
 * @author Franklin
 * @since 2021/08/21 12:38
 */
public class MapperUtils {

    public static MyMapper findMapper(@NotNull Project project, @NotNull String namespace, @NotNull String path) {
        List<XmlTag> mapperTags = findMappers(project, namespace);
        if (DataCheckUtils.isEmpty(mapperTags)){
            return null;
        }
        List<XmlTag> sortedMapperTags = mapperTags.stream()
            .map(xmlTag -> {
                String mapperPath = xmlTag.getContainingFile().getVirtualFile().getPath();
                String samePath = StringHelper.longestCommonSubString(mapperPath, path);
                return tuple(samePath.length(), xmlTag);
            })
            .sorted(Comparator.comparingInt(Tuple2::_1))
            .map(Tuple2::_2)
            .collect(Collectors.toList());
        XmlTag xmlTag = sortedMapperTags.get(sortedMapperTags.size() - 1);

        return new MyMapper(xmlTag);
    }

    public static List<XmlTag> findMappers(@NotNull Project project, @NotNull String namespace) {
        String simpleName = StringHelper.getSimpleName(namespace);
        PsiFile[] psiFiles = PsiUtils.findFiles(project, simpleName + ".xml");
        List<XmlTag> mapperTags = new PrettyArrayList<>();
        for (PsiFile psiFile : psiFiles) {
            if (DomUtils.isMybatisFile(psiFile)){
                XmlFile xmlFile = (XmlFile) psiFile;
                XmlTag mapperTag = xmlFile.getRootTag();
                Optional.ofNullable(mapperTag)
                    .filter(xmlTag -> StringHelper.equals(xmlTag.getName(), "mapper"))
                    .filter(xmlTag -> {
                        XmlAttribute namespaceAttr = xmlTag.getAttribute("namespace");
                        return Optional.ofNullable(namespaceAttr)
                            .map(XmlAttribute::getValue)
                            .map(value -> StringHelper.equals(value,namespace))
                            .orElse(false);
                    })
                    .ifPresent(mapperTags::add);
            }
        }
        return mapperTags;
    }

    public static String getNamespace(@NotNull Mapper mapper) {
        String ns = mapper.getNamespace().getStringValue();
        return null == ns ? "" : ns;
    }

    public static boolean isElementWithinMybatisFile(@NotNull PsiElement element) {
        PsiFile psiFile = element.getContainingFile();
        return element instanceof XmlElement && DomUtils.isMybatisFile(psiFile);
    }

    /**
     * 查找Mapper方法，一个Sql id 对应一个mapper方法，约定<br>
     * @author Franklin
     * @since 2021/9/7 10:14
     * @param project:
     * @param path:
     * @param mapperClassName:
     * @param methodName:
     * @return com.intellij.psi.PsiMethod
     */
    public static PsiMethod findMapperMethod(Project project, String path, String mapperClassName, String methodName){
        List<PsiMethod> psiMethodList = PsiUtils.findMethods(project, path, mapperClassName, methodName);
        if (DataCheckUtils.isEmpty(psiMethodList)){
            return null;
        }
        return psiMethodList.get(0);
    }
}
